2 // LiPoMetre pour télémesure Graupner Hott
4 // Gestion messagerie Hott
6 // Auteur : www.thyzoon.fr
11 #include "Tension_Lipo.h"
14 #define VERSION "0.60"
16 #define LEDPIN_OFF PORTB &= ~(1<<5);
17 #define LEDPIN_ON PORTB |= (1<<5);
18 // -------------------------------------
19 // Valeurs par défaut stockées en EEPROM
21 #define SEUIL_TENSION_ALARME 340 // 350 = 3.40V
22 #define SON_ALARME 9 // Bip
23 #define REPETITION_ALARME 15 // 15 s
28 static uint8_t _hott_serial_buffer
[173]; //création d'une variable tampon pour stocker les struct
30 // pointer des structures vers le tampon "_hott_serial_buffer"
31 struct HOTT_GAM_MSG
*hott_gam_msg
= (struct HOTT_GAM_MSG
*)&_hott_serial_buffer
[0];
32 struct HOTT_TEXTMODE_MSG
*hott_txt_msg
= (struct HOTT_TEXTMODE_MSG
*)&_hott_serial_buffer
[0];
34 word seuil_tension_alarme
; // seuil tension alarme (1 element)
35 word son_alarme
; // son alarme
36 word repetition
; // Repetition alarme
39 static uint8_t octet1
= 0; // reception
40 static uint8_t octet2
= 0; // reception
43 static uint8_t nb_Lipo
= 3; // Nb d'éléments accu Lipo
44 float Lipo_total
= 0; // Tension totale mesurée
45 float Lipo_Total_Mini
= 26; // Tension totale mini mesurée
46 float lipo1
= 0.0; // Tension sur chacun des éléments
52 float lipo_mini
= 0.0; // Valeur tension mini element
53 uint8_t Jauge
= 0; // Jauge carburant
54 uint8_t Alarme
= false; // Alarme tension basse
55 uint8_t Alarme_On
= false; // Alarme en marche
57 unsigned long temps
= 0; // Gestion du temps depuis mise sous tension en ms
58 unsigned long temps_alarme
= 0; // date de l'alarme de tension basse
61 // Sauvegardedes parametres en EEPROM
65 Maximum life of the EEPROM is 100000 writings/readings.
67 // Adresses des parametres en EEPROM, tous les parametres sont stockes sur 16 bits.
68 #define adr_eprom_init 0 // For the test for 1st time init of the Arduino (First power on)
69 #define adr_eprom_seuil_tension_alarme 2 // Tension seuil alarme
70 #define adr_eprom_son_alarme 4 // Son alarme
71 #define adr_eprom_repetition 6 // Repetition
74 extern TensionLipo tension
;
79 void GMessage::init(){
81 // Initialisation COM 19200 bauds pour recepteur HOTT GRxx
82 Serial
.begin (SERIAL_COM_SPEED
);
84 // ******************************************************
85 // Test for 1st time init of the Arduino (First power on)
86 int test
= read_eprom(adr_eprom_init
);
89 write_eprom(adr_eprom_init
,120);
90 write_eprom(adr_eprom_seuil_tension_alarme
,SEUIL_TENSION_ALARME
); // Seuil par défaut
91 write_eprom(adr_eprom_son_alarme
,SON_ALARME
); // Son par défaut
92 write_eprom(adr_eprom_repetition
,REPETITION_ALARME
);
94 // Read saved values from EEPROM
95 seuil_tension_alarme
= read_eprom(adr_eprom_seuil_tension_alarme
); // sens gaz Normal / Inversé
96 son_alarme
= read_eprom(adr_eprom_son_alarme
); // son alarme
97 repetition
= read_eprom(adr_eprom_repetition
); //
99 // Init. pour certaines données
106 setAltitudeInMeters (0);
112 nb_Lipo
= tension
.Detect (); // detection du nombre d'elements 2S a 6S
113 setTemp (nb_Lipo
,1); // affichage nb element a la place de Temp1
116 // Lecture d'un mot de 16 bits en EEPROM
117 uint16_t GMessage::read_eprom(int address
){
118 return (uint16_t) EEPROM
.read(address
) * 256 + EEPROM
.read(address
+1) ;
121 // Ecriture d'un mot de 16 bits en EEPROM
122 void GMessage::write_eprom(int address
,uint16_t val
){
123 EEPROM
.write(address
, val
/ 256);
124 EEPROM
.write(address
+1,val
% 256 );
127 // Initialisation message GAM (General Air Module)
128 void GMessage::init_gam_msg(){
129 //met tous à Zero, puis on modifie les constantes
130 memset(hott_gam_msg
, 0, sizeof(struct HOTT_GAM_MSG
));
131 hott_gam_msg
->start_byte
= 0x7c;
132 hott_gam_msg
->gam_sensor_id
= HOTT_TELEMETRY_GAM_SENSOR_ID
;
133 hott_gam_msg
->sensor_id
= 0xd0;
134 hott_gam_msg
->stop_byte
= 0x7d;
137 // Emission de la trame
138 void GMessage::send(int lenght
){
141 for(int i
= 0; i
< lenght
-1; i
++){
142 sum
= sum
+ _hott_serial_buffer
[i
];
143 Serial
.write (_hott_serial_buffer
[i
]);
144 delayMicroseconds(HOTTV4_TX_DELAY
);
146 Serial
.read(); // A cause du rebouclage TX <--> RX Lecture de l'octet émis
148 //Emision du checksum
150 delayMicroseconds(HOTTV4_TX_DELAY
);
151 Serial
.read(); // A cause du rebouclage TX <--> RX Lecture de l'octet émis
154 void GMessage::main(){
156 static byte page_settings
= 1;//numéro de la page de settings à afficher
158 if (Serial
.available() >= 2) {
159 uint8_t octet1
= Serial
.read();
161 case HOTT_BINARY_MODE_REQUEST_ID
:
163 uint8_t octet2
= Serial
.read();
164 // Demande RX Module = $80 $XX
166 case HOTT_TELEMETRY_GAM_SENSOR_ID
: //0x8D
171 // ******************************************************
174 // Mesure des tensions
175 lipo1
= tension
.Tension_Lipo1();
176 lipo2
= tension
.Tension_Lipo2();
177 lipo3
= tension
.Tension_Lipo3();
178 lipo4
= tension
.Tension_Lipo4();
179 lipo5
= tension
.Tension_Lipo5();
180 lipo6
= tension
.Tension_Lipo6();
182 // Calcul de la valeur de chaque elements
186 lipo2
= lipo2
- lipo1
;
191 lipo3
= lipo3
- lipo2
;
192 lipo2
= lipo2
- lipo1
;
198 lipo4
= lipo4
- lipo3
;
199 lipo3
= lipo3
- lipo2
;
200 lipo2
= lipo2
- lipo1
;
207 lipo5
= lipo5
- lipo4
;
208 lipo4
= lipo4
- lipo3
;
209 lipo3
= lipo3
- lipo2
;
210 lipo2
= lipo2
- lipo1
;
218 lipo6
= lipo6
- lipo5
;
219 lipo5
= lipo5
- lipo4
;
220 lipo4
= lipo4
- lipo3
;
221 lipo3
= lipo3
- lipo2
;
222 lipo2
= lipo2
- lipo1
;
236 setVoltage1(Lipo_total
); // Affichage sur Batt 1
237 setMainVoltage(Lipo_total
); // Affichage sur principal
239 if (Lipo_total
< Lipo_Total_Mini
) {
240 Lipo_Total_Mini
= Lipo_total
; // mémorise la valeur mini
241 setVoltage2(Lipo_Total_Mini
);
245 // Recherche element le plus faible
246 // pour affichage jauge
247 // et gestion alarme radio
248 lipo_mini
= tension
.Lipo_Mini(nb_Lipo
,lipo1
,lipo2
,lipo3
,lipo4
,lipo5
,lipo6
);
250 if ((lipo_mini
>= 3.6)&&(lipo_mini
<= 4.2))
251 Jauge
= 100 - (4.2 - lipo_mini
) / 0.0066667;
252 else if ((lipo_mini
< 3.6) && (lipo_mini
>= 3.0))
253 Jauge
= (lipo_mini
- 3.0) / 0.06 ;
254 else if (lipo_mini
< 3.0)
258 if (lipo_mini
< (float(seuil_tension_alarme
)/100.0))
263 if (Alarme_On
== true) {
264 alarme (son_alarme
); // Bip alarme
265 temps_alarme
= millis (); // temps courant
266 Alarme_On
= false; // Flag faux
269 alarme (ALARME_OFF
);} // fin d'alarme
271 // Affichage jauge carburant
272 setFuelPercent (Jauge
);
276 if (Alarme
== true) {
278 if (temps
> temps_alarme
+ (repetition
* 1000)) { // repetition entre alarmes
283 send(sizeof(struct HOTT_GAM_MSG
));
290 case HOTT_TEXT_MODE_REQUEST_ID
:
292 uint8_t octet3
= Serial
.read();
293 byte id_sensor
= (octet3
>> 4);
294 byte id_key
= octet3
& 0x0f;
295 static byte ligne_select
= 1 ; // Ligne 1 selectionnée par défaut
296 static int8_t ligne_edit
= -1 ;
297 hott_txt_msg
->start_byte
= 0x7b;
298 hott_txt_msg
->esc
= 0;
299 hott_txt_msg
->warning_beeps
= 0;
301 memset((char *)&hott_txt_msg
->text
, 0x20, HOTT_TEXTMODE_MSG_TEXT_LEN
);
302 hott_txt_msg
->stop_byte
= 0x7d;
304 if (id_sensor
== (HOTT_TELEMETRY_GAM_SENSOR_ID
& 0x0f))
307 switch (page_settings
) { // Pages de parametres LiPoMetre
311 if (ligne_edit
== -1)
315 ligne_select
= min(3,ligne_select
+ 1); // Ligne 2 maxi
319 ligne_select
= max(1,ligne_select
- 1); //Ligne 1 mini
322 case HOTT_KEY_SET
: // Sélection de la ligne courante
323 ligne_edit
= ligne_select
;
326 case HOTT_KEY_LEFT
: // Sortie
327 hott_txt_msg
->esc
= 0x01;
332 case HOTT_KEY_RIGHT
:
342 //*************************************************
343 //LIGNE 2 SELECTIONNEE = Seuil alarme
344 else if (ligne_select
== 1)
348 seuil_tension_alarme
= seuil_tension_alarme
+5;
349 if (seuil_tension_alarme
>380)
350 seuil_tension_alarme
= 380;
354 seuil_tension_alarme
= seuil_tension_alarme
-5;
355 if (seuil_tension_alarme
<300)
356 seuil_tension_alarme
= 300;
361 write_eprom(adr_eprom_seuil_tension_alarme
,seuil_tension_alarme
); // Ecriture en memoire
368 //*************************************************
369 //LIGNE 3 SELECTIONNEE = Son alarme
370 else if (ligne_select
== 2)
374 son_alarme
= son_alarme
+ 1;
380 son_alarme
= son_alarme
- 1;
387 write_eprom(adr_eprom_son_alarme
,son_alarme
); // Ecriture en memoire
394 //*************************************************
395 //LIGNE 4 SELECTIONNEE = Repetition alarme
396 else if (ligne_select
== 3)
400 repetition
= repetition
+ 5;
406 repetition
= repetition
- 5;
413 write_eprom(adr_eprom_repetition
,repetition
); // Ecriture en memoire
421 //******************************************************************************************
422 // Affichage de la page 1
424 snprintf((char *)&hott_txt_msg
->text
[0],21," * LiPoMetre V%s *",VERSION
);
426 snprintf((char *)&hott_txt_msg
->text
[1],21," Seuil alarme %i.%iV",int(seuil_tension_alarme
/100),int(seuil_tension_alarme
%100)) ; //float(seuil_tension_alarme)/100.0);
428 snprintf((char *)&hott_txt_msg
->text
[2],21," Son alarme %2i",son_alarme
);
430 snprintf((char *)&hott_txt_msg
->text
[3],21," Repet. alarme %2is",repetition
);
432 snprintf((char *)&hott_txt_msg
->text
[4],21," ------------------- ");
434 snprintf((char *)&hott_txt_msg
->text
[5],21," LIPO %iS", nb_Lipo
);
436 snprintf((char *)&hott_txt_msg
->text
[6],21," ------------------- ");
438 snprintf((char *)&hott_txt_msg
->text
[7],21," thyzoon.fr 2015");
440 hott_txt_msg
->text
[ligne_select
][0] = '>';
441 _hott_invert_ligne(ligne_edit
);
454 //********************************************************************************************************************
456 else if(id_sensor
== (HOTT_TELEMETRY_GEA_SENSOR_ID
& 0x0f)) {
457 snprintf((char *)&hott_txt_msg
->text
[0],21,"Module EAM");
458 snprintf((char *)&hott_txt_msg
->text
[1],21,"----------");
459 snprintf((char *)&hott_txt_msg
->text
[2],21,"Selectionner :");
460 snprintf((char *)&hott_txt_msg
->text
[3],21," GENERAL");
462 else if(id_sensor
== (HOTT_TELEMETRY_VARIO_SENSOR_ID
& 0x0f)) {
463 snprintf((char *)&hott_txt_msg
->text
[0],21,"Module VARIO");
464 snprintf((char *)&hott_txt_msg
->text
[1],21,"------------");
465 snprintf((char *)&hott_txt_msg
->text
[2],21,"Selectionner :");
466 snprintf((char *)&hott_txt_msg
->text
[3],21," GENERAL");
469 snprintf((char *)&hott_txt_msg
->text
[0],21,"Module inconnu");
470 snprintf((char *)&hott_txt_msg
->text
[1],21,"--------------");
471 snprintf((char *)&hott_txt_msg
->text
[2],21,"Selectionner :");
472 snprintf((char *)&hott_txt_msg
->text
[3],21," GENERAL");
475 // Emission en mode texte
476 _hott_send_text_msg();
483 //////////////////////////////////////////////////
484 // Tension principale (resolution 0.1V)
485 void GMessage::setMainVoltage(float tension
){
486 hott_gam_msg
->main_voltage
= (uint16_t) (tension
* 10);
489 // Batterie 1 (resolution 0.1V)
490 void GMessage::setVoltage1(float volt
){
491 hott_gam_msg
->Battery1
= (uint16_t) (volt
* 10);
494 // Batterie 2 (resolution 0.1V)
495 void GMessage::setVoltage2(float volt
){
496 hott_gam_msg
->Battery2
= (uint16_t) (volt
* 10);
499 // Element Lipo n (resolution 0.02V)
500 void GMessage::setLipo(float volt
, int lipo
){
502 if (lipo
>= 1 and lipo
<= 6)
505 hott_gam_msg
->cell
[lipo
] = (uint16_t) 100 * volt
/ 2 ;
507 if (volt
/2 <= hott_gam_msg
->min_cell_volt
|| hott_gam_msg
->min_cell_volt
==0)
509 hott_gam_msg
->min_cell_volt
= (uint16_t) 100 * volt
/2 ;
510 hott_gam_msg
->min_cell_volt_num
= lipo
;
515 // Altitude relative en metres : -500 / +9999 [m]
516 void GMessage::setAltitudeInMeters(uint16_t alti
){
517 hott_gam_msg
->altitude
= alti
+ 500;
520 // Temperature : -20 a +235° C
522 void GMessage::setTemp(int temp
, int capteur
){
532 hott_gam_msg
->temperature1
= temp
+ 20;
533 else if (capteur
== 2)
534 hott_gam_msg
->temperature2
= temp
+ 20;
537 // Niveau reservoir : 0%, 25%, 50%, 75%, 100%
539 void GMessage::setFuelPercent(uint8_t pourcent
){
542 else if(pourcent
< 0)
544 hott_gam_msg
->fuel_procent
= pourcent
;
547 // niveau reservoir en ml : 0 a 65535 ml
549 void GMessage::setFuelMilliliters(uint16_t ml
){
550 hott_gam_msg
->fuel_ml
= ml
;
553 // Rotation : 0 a 655350 tr/min
556 void GMessage::setRPM(uint16_t rpm
){
557 hott_gam_msg
->rpm
= rpm
;
561 void GMessage::setClimbrate(uint16_t climb_L
){
562 hott_gam_msg
->climbrate_L
= climb_L
+30000;
565 void GMessage::setClimbrate_M3(int climb3s
){
566 hott_gam_msg
->climbrate3s
= climb3s
+120;
570 void GMessage::setSpeed(float speed
){
571 hott_gam_msg
->climbrate3s
= (int) speed
;
576 // Alarme sonore sur radio
578 void GMessage::alarme (uint8_t son
){
579 hott_gam_msg
->warning_beeps
= son
;
582 void GMessage::_hott_send_text_msg() {
583 for(byte
*_hott_msg_ptr
= hott_txt_msg
->text
[0]; _hott_msg_ptr
< &hott_txt_msg
->stop_byte
; _hott_msg_ptr
++){
584 if (*_hott_msg_ptr
== 0)
585 *_hott_msg_ptr
= 0x20;
587 //_hott_send_msg(_hott_serial_buffer, sizeof(struct HOTT_TEXTMODE_MSG));
588 send(sizeof(struct HOTT_TEXTMODE_MSG
));
591 char * GMessage::_hott_invert_all_chars(char *str
) {
592 return _hott_invert_chars(str
, 0);
595 char * GMessage::_hott_invert_chars(char *str
, int cnt
) {
596 if(str
== 0) return str
;
597 int len
= strlen(str
);
598 if((len
< cnt
) && cnt
> 0) len
= cnt
;
599 for(int i
=0; i
< len
; i
++) {
600 str
[i
] = (byte
)(0x80 + (byte
)str
[i
]);
605 void GMessage::_hott_invert_ligne(int ligne
) {
606 if (ligne
>= 0 && ligne
<= 7)
607 for(int i
=0; i
< 21; i
++) {
608 if (hott_txt_msg
->text
[ligne
][i
] == 0) //inversion du caratère null (fin de string)
609 hott_txt_msg
->text
[ligne
][i
] = (byte
)(0x80 + 0x20);
611 hott_txt_msg
->text
[ligne
][i
] = (byte
)(0x80 + (byte
)hott_txt_msg
->text
[ligne
][i
]);